//
//  rgk.c
//  RetroGameKit
//
//  Created by Michael Burns on 10/27/13.
//  Copyright (c) 2013 Michael Burns. All rights reserved.
//

#include <stdio.h>
#include <iostream>

#include "rgk.h"

RGKDisplay *display;

int RGKDisplayInit(int screen_width, int screen_height, const char *caption, double zoomFactor)
{
    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        printf("Could not initialize SDL\n");
        return 1;
    }
    
    display = (RGKDisplay *)malloc(sizeof(RGKDisplay));
    display->window = SDL_CreateWindow(
        caption,
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        screen_width,
        screen_height,
        SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_RENDERER_ACCELERATED
    );
    
    display->w = screen_width;
    display->h = screen_height;
    display->zoomFactor = zoomFactor;
    
    if(display->window == NULL)
    {
        return 1;
    }
    
    display->renderer = SDL_CreateRenderer(display->window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
    
    if(SDL_Init(SDL_INIT_AUDIO) < 0)
        printf("SDL_Init: %s\n", SDL_GetError());

    if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048)==-1)
        printf("Mix_OpenAudio: %s\n", Mix_GetError());
        
    return 1;
}

void RGKDisplayQuit()
{
    if(display != NULL)
    {
        SDL_DestroyRenderer(display->renderer);
        SDL_DestroyWindow(display->window);
        free(display);
        display = NULL;
    }
    SDL_Quit();
}

void RGKDisplayClear(int r, int g, int b)
{
    SDL_SetRenderDrawColor(display->renderer, r, g, b, 255);
    SDL_RenderClear(display->renderer);
}

void RGKDisplayPresent()
{
    SDL_RenderPresent(display->renderer);
}

void RGKCapFramerate(double fps)
{
    static double start = 0, diff, wait;
    wait = 1000 / fps;
    diff = SDL_GetTicks() - start;
    if (diff < wait) {
        SDL_Delay(wait - diff);
    }
    start = SDL_GetTicks();
}

int RGKPollEvent(RGKEvent *e)
{
    SDL_Event evt;
    int r = SDL_PollEvent(&evt);
    if(evt.key.repeat && evt.type != SDL_QUIT)
        return r;
    switch(evt.type)
    {
        case SDL_QUIT:
            e->type = RGK_QUIT;
            break;
        case SDL_KEYDOWN:
            e->type = RGK_KEYDOWN;
            break;
        case SDL_KEYUP:
            e->type = RGK_KEYUP;
            break;
        case SDL_MOUSEBUTTONDOWN:
            e->type = RGK_MOUSEBUTTONDOWN;
            break;
        case SDL_MOUSEBUTTONUP:
            e->type = RGK_MOUSEBUTTONUP;
            break;
        case SDL_MOUSEMOTION:
            e->type = RGK_MOUSEMOTION;
            break;
        default:
            e->type = 0;
            break;
    }
    e->key = evt.key.keysym.scancode;
    e->button = evt.button.button;
    e->x = evt.button.x / display->zoomFactor;
    e->y = evt.button.y / display->zoomFactor;
    return r;
}

const Uint8 *RGKGetKeyboardState(int *numkeys)
{
    return SDL_GetKeyboardState(numkeys);
}

RGKRect RGKRectMake(double x, double y, double w, double h)
{
    RGKRect r = {x, y, w, h};
    return r;
}

RGKRect RGKRectMove(RGKRect r, double dx, double dy)
{
    return RGKRectMake(r.x + dx, r.y + dy, r.w, r.h);
}

int RGKRectIntersects(RGKRect rect1, RGKRect rect2)
{
    return ((rect1.x >= rect2.x && rect1.x < rect2.x + rect2.w)  ||
            (rect2.x >= rect1.x && rect2.x < rect1.x + rect1.w)) &&
           ((rect1.y >= rect2.y && rect1.y < rect2.y + rect2.h)  ||
            (rect2.y >= rect1.y && rect2.y < rect1.y + rect1.h));
}

RGKImage *RGKImageLoad(const char *filename)
{
    if(display != NULL)
    {
        RGKImage *img = (RGKImage *)malloc(sizeof(RGKImage));
        img->tex = IMG_LoadTexture(display->renderer, filename);
        if(!img->tex)
            printf("error loading %s\n", filename);
        
        SDL_QueryTexture(img->tex, NULL, NULL, &(img->w), &(img->h));
        return img;
    }
    return NULL;
}

void RGKImageFree(RGKImage *image)
{
    if(image != NULL)
    {
        SDL_DestroyTexture(image->tex);
        free(image);
    }
}

void RGKImageDraw(RGKImage *image, RGKRect dest, RGKRect src, double angle, int flip_x, int flip_y)
{
    double zf = display->zoomFactor;
    image->src.x = (int)src.x;
    image->src.y = (int)src.y;
    image->src.w = (int)src.w;
    image->src.h = (int)src.h;
    image->dst.x = (int)(dest.x * zf);
    image->dst.y = (int)(dest.y * zf);
    image->dst.w = (int)(dest.w * zf);
    image->dst.h = (int)(dest.h * zf);
    SDL_RendererFlip flip_flags = SDL_FLIP_NONE;
    if(flip_x) flip_flags = (SDL_RendererFlip)(flip_flags | SDL_FLIP_HORIZONTAL);
    if(flip_y) flip_flags = (SDL_RendererFlip)(flip_flags | SDL_FLIP_VERTICAL);
    SDL_RenderCopyEx(display->renderer, image->tex, &image->src, &image->dst,
                     angle, NULL, flip_flags);
}

RGKSound *RGKSoundLoad(const char *filename)
{
    RGKSound *sound = (RGKSound *)malloc(sizeof(RGKSound));
    sound->chunk = Mix_LoadWAV(filename);
    if(sound->chunk == NULL)
        return NULL;
    return sound;
}

void RGKSoundFree(RGKSound *sound)
{
    Mix_FreeChunk(sound->chunk);
    free(sound);
}

void RGKSoundPlay(RGKSound *sound, int loops)
{
    Mix_PlayChannel(-1, sound->chunk, loops);
}

void RGKSoundSetVolume(RGKSound *sound, double volume)
{
    Mix_VolumeChunk(sound->chunk, volume * MIX_MAX_VOLUME);
}

RGKMusic *RGKMusicLoad(const char *filename)
{
    RGKMusic *music = (RGKMusic *)malloc(sizeof(RGKMusic));
    music->music = Mix_LoadMUS(filename);
    if(!music->music)
        printf("error loading: %s - %s\n", filename, Mix_GetError());
    return music;
}

void RGKMusicFree(RGKMusic *music)
{
    Mix_FreeMusic(music->music);
    free(music);
}

void RGKMusicPlay(RGKMusic *music, int loops)
{
    Mix_PlayMusic(music->music, -1);
}

void RGKMusicStop()
{
    Mix_HaltMusic();
}

void RGKMusicPause()
{
    Mix_PauseMusic();
}

void RGKMusicResume()
{
    Mix_ResumeMusic();
}

void RGKMusicSetVolume(double volume)
{
    Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}
